﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;

namespace Mechatronics.Robotics.Transports
{
    public class TransportRS232 : ITransport
    {
        SerialPort serialPort;

        /// <summary>
        /// Initializes connection
        /// </summary>
        /// <param name="Port name"></param>
        /// <param name="Baund rate (port speed)"></param>
        public TransportRS232(string portname, int baudrate)
        {
            if (string.IsNullOrEmpty(portname))
                throw new ArgumentNullException("portname");

            if (baudrate <= 0)
                throw new ArithmeticException("baudrate");

            this.serialPort = new SerialPort(portname, baudrate);
        }

        /// <summary>
        /// Opens port and settings up connection
        /// </summary>
        public void Connect()
        {
            serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
            this.serialPort.Open();
            serialPort.ReceivedBytesThreshold = 5;
        }

        void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (DataReceived != null)
                DataReceived(Encoding.ASCII.GetBytes(serialPort.ReadExisting()));
        }

        /// <summary>
        /// Closes port
        /// </summary>
        public void Disconnect()
        {
            this.serialPort.Close();
        }

        /// <summary>
        /// Sends data
        /// </summary>
        /// <param name="data"></param>
        public void Send(byte[] data)
        {
            if (!serialPort.IsOpen)
                throw new InvalidOperationException("Connection closed");

            this.serialPort.Write(data, 0, data.Length);
        }

        /// <summary>
        /// Returns all available data
        /// </summary>
        /// <returns></returns>
        public byte[] Receive()
        {
            if (!serialPort.IsOpen)
                throw new InvalidOperationException("Connection closed");

            return Encoding.ASCII.GetBytes(this.serialPort.ReadExisting());
        }

        /// <summary>
        /// Checks if connection is open
        /// </summary>
        public bool IsConnected
        {
            get
            {
                return this.serialPort.IsOpen;
            }
        }

        /// <summary>
        /// Waits for data and returns it
        /// </summary>
        /// <param name="Number of bytes"></param>
        /// <returns></returns>
        public byte[] Receive(int count)
        {
            byte[] buffer = new byte[count];
            int received_bytes = 0;
            do
            {
                received_bytes += this.serialPort.Read(buffer, received_bytes, count - received_bytes);
            } while (received_bytes != count);

            return buffer;
        }

        public DataReceivedEvent DataReceived { get; set; }
    }
}
